/* *  
 * Copyright (C) 2004-2008 Mocha Almond Fudge AI, SIT KMUTT
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package jboard.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;

import jboard.model.BoardPosition;
import jboard.model.IBoardConstant;

/**
 * This class is Graphic User Interface of Board game, which know how to render
 * itself.<br>
 * 
 * @author Vashira Ravipanich
 */
public class BoardGUI extends JFrame  implements IBoardConstant {
    /** JBoard component*/
    private JPanel boardPanel;
    private JRadioButtonMenuItem centerStrategyMenuItem;
    private BoardPosition currentBPS;
    private JPanel gamePanel;
    private JRadioButtonMenuItem leftStrategyMenuItem;
    private JCheckBoxMenuItem moveMenuIterm;
    /** Swing components */
    private JMenuItem nGameMenuItem;
    private JCheckBoxMenuItem reverseTokenMenuItem; 
    private JRadioButtonMenuItem rightStrategyMenuItem;
    private JLabel statusLabel;
    private JTextArea statusTextArea;
    private JRadioButtonMenuItem stdThemeItem, freezeThemeItem;
    private JLayeredPane theLayeredPane;
    private String theme = STANDARD; // Default theme
    private JMenu threePile;
    /** Set interactive score and avatar*/
    private TokenPanel tokenPanel;
    private JCheckBoxMenuItem twoPileCMenuItem;
    
    
    /**
     * Default constructor
     * 
     * @param title		Title of JFrame
     */
    public BoardGUI(String title) {
        super(title);
        initBoard(this.theme);
        initComponents();
    }
    
    /**
     * Add action listener to GUI (Menu: Game)
     * 
     * @param listener
     */
    public void addActionListener(ActionListener listener) {
        nGameMenuItem.addActionListener(listener);	// For new game action
    }
    
    public void addHandler(Handler handler) {
    	theLayeredPane.addMouseMotionListener(handler.getMotionHandler());
    	theLayeredPane.addMouseListener(handler.getInputHandler());
    }
    
    /**
     * Add Item listener to GUI (Menu: Options, )
     * 
     * @param listener
     */
    public void addItemListener(ItemListener listener) {
        /** Options*/
        moveMenuIterm.addItemListener(listener); // For determine who move first (AI || Player)
        reverseTokenMenuItem.addItemListener(listener);	// For determine token initialize order
        /** Theme*/
        stdThemeItem.addItemListener(listener);
        freezeThemeItem.addItemListener(listener);
        /** AI config*/
        twoPileCMenuItem.addItemListener(listener);
        leftStrategyMenuItem.addItemListener(listener);
        rightStrategyMenuItem.addItemListener(listener);
        centerStrategyMenuItem.addItemListener(listener);
    }
    
    /**
     * Clear Console (in GUI)
     */
    public void clearLog() {
        statusTextArea.setText("");
    }
    
    public JPanel getBoardPanel() {
        return boardPanel;
    }
    
    public BoardPosition getCurrentBPS() {
        return currentBPS;
    }
    
    /**
     * @return Returns the theme.
     */
    public String getTheme() {
        return theme;
    }
    
    /**
     * @return Returns the tokenPanel.
     */
    public TokenPanel getTokenPanel() {
        return tokenPanel;
    }
    
    /**
     * Initial Board
     */
    private void initBoard(String theme) {
        boardPanel =  new JPanel();
        theLayeredPane = new JLayeredPane();
        /** 
         * Use ThemeFactory render BG instead
         */
        theLayeredPane.setPreferredSize(new Dimension(CELL_SIZE * 8 + 2, CELL_SIZE * 8 + 2));
        theLayeredPane = ThemeFactory.renderBG(theLayeredPane, theme);
        boardPanel.add(theLayeredPane);
    }
        
    /**
     * Initial swing components
     *
     */
    private void initComponents() {
        /**Set Swing components */
		this.getContentPane().setLayout(new BorderLayout());
		
		final JPanel creditPanel = new JPanel();
        this.getContentPane().add(creditPanel, BorderLayout.NORTH);
        
        final JLabel label = new JLabel();
        label.setFont(new Font("Tahoma", Font.BOLD, 12));
        creditPanel.add(label);
        label.setText("CSC340 - Mak-Neeb by Nop, Som, & Vashira Ravipanich");
        
        final JPanel statusPanel = new JPanel();
        statusPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
        statusPanel.setLayout(new BorderLayout());
        getContentPane().add(statusPanel, BorderLayout.SOUTH);
        
        statusLabel = new JLabel();
        statusPanel.add(statusLabel);
        statusLabel.setText("Status");
        
        /** Main Part */
        final JSplitPane mainSplitPane = new JSplitPane();
        mainSplitPane.setDividerLocation(-1);	// 140
        mainSplitPane.setDividerSize(5);
        getContentPane().add(mainSplitPane, BorderLayout.CENTER);
        
        gamePanel = new JPanel();
        gamePanel.setLayout(new BorderLayout());
        mainSplitPane.setLeftComponent(gamePanel);
        
        // create string panel (A-H), (1-8)
        final HLabelPanel upperConstantPanel = new HLabelPanel();
        final HLabelPanel lowerConstantPanel = new HLabelPanel();
        final VLabelPanel leftConstantPanel = new VLabelPanel();
        final VLabelPanel rightConstantPanel = new VLabelPanel();
        gamePanel.add(upperConstantPanel, BorderLayout.NORTH);
        gamePanel.add(lowerConstantPanel, BorderLayout.SOUTH);
        gamePanel.add(leftConstantPanel, BorderLayout.WEST);
        gamePanel.add(rightConstantPanel, BorderLayout.EAST);
        
        // add boardPanel to the gamePanel
        gamePanel.add(boardPanel, BorderLayout.CENTER);
        
        // mainRightPanel = tokenPanel + consolePanel
        final JPanel mainRightPanel = new JPanel();
        mainRightPanel.setLayout(new BorderLayout());
        
        tokenPanel = new TokenPanel();
        mainRightPanel.add(tokenPanel, BorderLayout.NORTH);
        
        // console Panel
        final JPanel consolePanel = new JPanel();
        final BorderLayout borderLayout = new BorderLayout();
        consolePanel.setBorder(new TitledBorder(null, "JConsole", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        consolePanel.setLayout(borderLayout);
        mainRightPanel.add(consolePanel, BorderLayout.CENTER);

        mainSplitPane.setRightComponent(mainRightPanel);
        
        final JPanel buttonPanel = new JPanel();
        buttonPanel.setPreferredSize(new Dimension(200, 30));	// trick to set concolePanel size
        consolePanel.add(buttonPanel, BorderLayout.SOUTH);

        final JButton saveButton = new JButton();
        buttonPanel.add(saveButton);
        saveButton.setText("Save");
        saveButton.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		saveLog();
        	}
        });

        final JButton clearButton = new JButton();
        buttonPanel.add(clearButton);
        clearButton.setText("Clear");
        clearButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clearLog();
            }
        });
        
        final JScrollPane scrollPane = new JScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        consolePanel.add(scrollPane, BorderLayout.CENTER);

        statusTextArea = new JTextArea();
        statusTextArea.setMargin(new Insets(0, 5, 0, 0));
        statusTextArea.setForeground(Color.YELLOW);
        statusTextArea.setFont(new Font("@SimSun", Font.PLAIN, 12));
        statusTextArea.setBackground(Color.BLACK);
        statusTextArea.setLineWrap(true);
        scrollPane.setViewportView(statusTextArea);
        statusTextArea.setEditable(false);
        
        /** Menu part */
        final JMenuBar mainMenuBar = new JMenuBar();
        setJMenuBar(mainMenuBar);
        
        // Menu: Game
        final JMenu gameMenu = new JMenu();
        mainMenuBar.add(gameMenu);
        gameMenu.setText("Game");

        // Game > New Game
        nGameMenuItem = new JMenuItem();
        gameMenu.add(nGameMenuItem);
        nGameMenuItem.setText("New game");

        gameMenu.addSeparator();

        // Game > Exit
        final JMenuItem exitMenuItem = new JMenuItem();
        exitMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        gameMenu.add(exitMenuItem);
        exitMenuItem.setText("Exit");

        // Menu: Options
        final JMenu optionsMenu = new JMenu();
        mainMenuBar.add(optionsMenu);
        optionsMenu.setText("Options");

        moveMenuIterm = new JCheckBoxMenuItem();
        moveMenuIterm.setSelected(true);
        optionsMenu.add(moveMenuIterm);
        moveMenuIterm.setText("Player move first");
        
        reverseTokenMenuItem = new JCheckBoxMenuItem();
        reverseTokenMenuItem.setSelected(false);
        optionsMenu.add(reverseTokenMenuItem);
        reverseTokenMenuItem.setText("Reverse Pawn Order");
        
        // Menu: AI
        final JMenu aiMenu = new JMenu();
        mainMenuBar.add(aiMenu);
        aiMenu.setText("AI config");
        
        twoPileCMenuItem = new JCheckBoxMenuItem();
        twoPileCMenuItem.setText("2 Pile look ahead");
        twoPileCMenuItem.setSelected(true);
        aiMenu.add(twoPileCMenuItem);
        
        threePile = new JMenu();
        threePile.setText("3 Pile look ahead");
        ButtonGroup aiGroup = new ButtonGroup();
        
        leftStrategyMenuItem = new JRadioButtonMenuItem();
        aiGroup.add(leftStrategyMenuItem);
        leftStrategyMenuItem.setText("Left strategy");
        
        rightStrategyMenuItem = new JRadioButtonMenuItem();
        aiGroup.add(rightStrategyMenuItem);
        rightStrategyMenuItem.setText("Right strategy");
        
        centerStrategyMenuItem = new JRadioButtonMenuItem();
        aiGroup.add(centerStrategyMenuItem);
        centerStrategyMenuItem.setText("Center strategy");
        
        threePile.add(leftStrategyMenuItem);
        threePile.add(rightStrategyMenuItem);
        threePile.add(centerStrategyMenuItem);
        aiMenu.add(threePile);
        
        // Menu: Themes
        final JMenu themesMenu = new JMenu();
        mainMenuBar.add(themesMenu);
        themesMenu.setText("Themes");
        ButtonGroup themeGroup = new ButtonGroup();
        
        // Submenu: Themes > standard
        stdThemeItem = new JRadioButtonMenuItem();
        stdThemeItem.setText("standard");
        stdThemeItem.setSelected(true); // default theme for now!
        
        // Submenu: Themes > freeze
        freezeThemeItem = new JRadioButtonMenuItem(); 
        freezeThemeItem.setText("freeze");
        
        themeGroup.add(stdThemeItem);
        themeGroup.add(freezeThemeItem);
        
        themesMenu.add(stdThemeItem);
        themesMenu.add(freezeThemeItem);
        
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		this.pack();
		this.setResizable(false);
		this.setVisible(true);
    }
    
    /**
     * Log everything to Console (in GUI)
     *  
     * @param message
     */
    public void log(String message, boolean isEndLine) {
        if(isEndLine)
            statusTextArea.append(message + '\n');
        else
            statusTextArea.append(message);
    }
    
    public void removeHandler(Handler handler) {
        theLayeredPane.removeMouseMotionListener(handler.getMotionHandler());
        theLayeredPane.removeMouseListener(handler.getInputHandler());
    }
    
    /**
     * Render token (pawn) on the Board GUI
     * 
     * @param currentPos
     */
    public void renderBoard() {
        JLayeredPane thePane = (JLayeredPane)boardPanel.getComponent(0);
        
		Component[] list = thePane.getComponentsInLayer(TOKEN_LAYER);
		for(int i = 0; i < list.length; i++) {
			list[i].setVisible(false);
			thePane.remove(list[i]);
		}
        
        for(int x = 0; x < 8; x++) {
			for(int y = 0; y < 8; y++) {	    
			    int token;
			    if(currentBPS.peek(x, y) == WHITE) 
			        token = WHITE;
			    else if(currentBPS.peek(x, y) == BLACK)
			        token = BLACK;
			    else
			        continue;
			 
			    JLabel pi2 = ThemeFactory.createToken(this.theme, token);
			    pi2.setBounds(0, 0, CELL_SIZE, CELL_SIZE);
				pi2.setLocation(x * CELL_SIZE, y * CELL_SIZE);
				thePane.add(pi2, new Integer(TOKEN_LAYER));	// board layer 2 (token)
			}
        }
    }
    
    /**
     * Render theme
     */
    public void renderTheme() {
        gamePanel.remove(boardPanel);
        this.setVisible(false);
        initBoard(this.theme);
        gamePanel.add(boardPanel, BorderLayout.CENTER);
        this.setVisible(true);
    }
    
    public void saveLog() {
    	try {
    		JFileChooser chooser = new JFileChooser();
    	    if(chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
    	    	String filename = chooser.getSelectedFile().getAbsolutePath();
    	    	PrintWriter logFile = new PrintWriter(new BufferedWriter(
    	    			new FileWriter(filename)));
    			logFile.write(statusTextArea.getText());
    			logFile.flush();
    			logFile.close();
    	    }
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    public void setCurrentBPS(BoardPosition currentBPS) {
        this.currentBPS = currentBPS;
    }
    
    public void setStatus(String status) {
        this.statusLabel.setText(status);
    }
    
    /**
     * @param theme The theme to set.
     */
    public void setTheme(String theme) {
        this.theme = theme;
        System.out.println("In BoardGUI.setTheme(): now theme is " + this.theme);
    }
    
    public void testStateChange() {
        System.out.println("State change!");
    }
}
